%TODO[jenda, honza] přečíst a připomínkovat
\documentclass[12pt, titlepage]{article}
\usepackage[utf8]{inputenc}
\usepackage[czech]{babel}
\usepackage[pdftex]{graphicx}
\usepackage{graphicx}
\usepackage{epstopdf}
\usepackage{a4wide}
\usepackage{listings}

\title{\textsc{Simulace operačního systému}\\KIV/OS -- Semestrální práce}
\author{
Martin Štulc -- A11N0131P -- martin.stulc@gmail.com\\
Jan Šváb -- A080061P -- jansvab10@centrum.cz\\
Jan Kolena -- A11N0112P -- jendakolena@gmail.com}
\date{\today}
\begin{document}
\begin{titlepage}
\begin{figure}
\includegraphics[width=5cm]{obr/logo.png}
\end{figure}
\maketitle
\end{titlepage}
	
\section{Zadání}
Naprogramujte simulátor operačního systému, který bude umožňovat vykonávat dané příkazy:
\begin{itemize}
\item cat -- vypíše soubor
\item cd -- změní pracovní adresář shellu
\item echo -- vypíše zprávu
\item exit -- ukončí shell
\item kill -- ukončí proces
\item ls -- vypíše obsah pracovního adresáře; ls -- vypisuje aktuální adresář; ls rel\_cesta; ls abs\_cesta
\item man -- vypíše stručnou nápovědu a všechny implementované příkazy
\item ps -- vypíše všechny procesy v modelu (výpis kompletně všech procesů -- kvůli ladění)
\item pwd -- vypíše pracovní adresář shellu
\item shell -- spustí shell (lze spouštět rekurzivě)
\item shutdown -- ukončí běh modelu; ne pouhé volání Sytem.exit, ale volání služby, která nejprve ukončí všechny procesy, \dots a až na konec zavolá System.exit (pouze pokud je potřeba)
\item sort -- seřadí řádky ze vstupu a vypíše je na výstup
\item Uchovávejte historii příkazů
\end{itemize}




\section{Uživatelská dokumentace}
\subsection{Překlad a spuštění}
%TODO[jenda]
K překladu slouží skript \textit{compile.bat}, který vytvoří složku build a do ní JAR soubor \texttt{m2jos.jar}. Jeho spuštěním, například pomocí skriptu \textit{run.bat} dojde ke spuštění virtuálního stroje.

\subsection{Běh aplikace}
Po spuštění programu se zobrazí přihlašovací okno (viz obrázek \ref{login}).
\begin{figure}[h!]
\centering
\includegraphics[width=200px]{obr/login}
\caption{Přihlašovací okno.}
\label{login}
\end{figure}
Na loginu ani hesle nezáleží. Login bude použit pouze jako jméno přihlášeného uživatele. Toto okno je aktivní po celou dobu běhu virtuálního stroje (aplikace). Je tedy možné přihlásit se vícenásobně. Při ukončení tohoto okna dojde i k ukončení všech shellů i celého virtuálního stroje.
\par
Po přihlášení se spustí okno shellu (viz obrázek \ref{shell}).
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/shell}
\caption{Okno shellu.}
\label{shell}
\end{figure}
V horní části vidíme historii příkazů, kde uživatelský vstup vždy začíná znakem \texttt{>}, v dolní pak prompt, který ukazuje aktuální cestu, nebo jméno příkazu, který žádá o uživatelský vstup.
\par
Po kliknutí pod tento prompt je možné zadávat vstup. Je-li v promptu cesta jedná se o vstup shellu -- příkazy. Každý příkaz může mít přesměrován vstup resp. výstup pomocí konstukce \texttt{příkaz\_s\_parametry~<jméno\_souboru} resp. \texttt{příkaz\_s\_parametry~>jméno\_souboru}.
Nebo může mít přesměrován výstup na vstup jineho příkazu pomocí konstrukce \texttt{pří\-kaz1\_s\_parametry~|~příkaz2\_s\_parametry}.
\par
Při vykonávání příkazu není možné spouštět další příkazy, ale může být požadován uživatelský vstup. V tomto případě se prompt změní na jméno příkazu, který vstup vyžaduje (viz obrázek \ref{vstup}).
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/vstup}
\caption{Okno shellu s uživatelským vstupem požadovaným příkazem \texttt{sort}.}
\label{vstup}
\end{figure}
Uživatelský vstup je možné ukončit kombinací kláves \texttt{CTRL+D}.
\par
Při psaní je možné používat směrové šipky nahoru a dolů pro listování v historii příkazů.
\par
Uživatelskou dokumentaci lze zobrazit pomocí příkazu \texttt{man} a nápovědu k jednotlivým příkazům pak pomocí příkazu \texttt{man~\textit{<jméno\_příkazu>}}.
\par
Shell lze spouštět rekurzivně pomocí příkazu \texttt{shell}. V tomto případě je možné používat oba shelly současně. Při ukončení rodičovského shellu dojde i k ukončení shellu dceřinného. Shell lze ukončit pomocí příkazu \texttt{exit} nebo můžeme ukončit celý virtuální stroj pomocí příkazu \texttt{shutdown}.





\section{Programátorská dokumentace}
\subsection{Objektový návrh}

\subsubsection{Spuštění programu (viz obrázek \ref{spusteni})}
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/01_spusteni_programu}
\caption{UML diagram spuštění programu.}
\label{spusteni}
\end{figure}
Třída \texttt{Main} pomocí \texttt{IProcessCreatoru} vytvoří \texttt{InitProcess}, který běží ve vlastním vlákně. Ten pak vytvoří přihlašovací okno \texttt{MainWindow}.

\subsubsection{Spuštění shellu (viz obrázek \ref{shell})}
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/02_shell}
\caption{UML diagram spuštění shellu.}
\label{shell}
\end{figure}
Přihlašovací okno zavolá přes \texttt{initProcess} vytvoření potomka a předá mu handle s přihlašovacími údaji. Jako jméno procesu (\textit{commandName}) uvede \textit{shell}. \texttt{InitProcess} pomocí \texttt{ProcessCreatoru} potomka vytvoří a díky \textit{commandName} vybere \texttt{IProcessCreator} \texttt{shell}. \texttt{Shell} vytvoří vyvolá okno shellu (\texttt{IShellWindow}) a vytvoří tři streamy (viz obrázek \ref{streamy}) pro vstup, výstup a chybový výstup, jejichž konce (vstupy či výstupy) nastaví na interakci s uživatelem v oknu shellu.
\par
Tyto streamy pak čekají na uživatelský vstup, či požadavek na výstup.



\subsubsection{Příkaz zadaný uživatelem (viz obrázky \ref{streamy} a \ref{process})}
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/03_shell_process}
\caption{UML diagram streamů shellu a vytváření nového procesu.}
\label{streamy}
\end{figure}
\texttt{Shell} pomocí \texttt{IAnalyzeru} zanalyzuje vstup uživatele a vytvoří \texttt{IHandle}.
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/04_vytvoreni_procesu}
\caption{UML diagram vytvoření nového procesu po zadání příkazu v shellu.}
\label{process}
\end{figure}
Tento \texttt{IHandle} je pak předán \texttt{IProcessCreatoru}, který vytvoří nový process jako dceřinný process \texttt{Shellu}.

\subsubsection{Pipe (viz obrázek \ref{pipe})}
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/05_pipe}
\caption{UML diagram použití roury.}
\label{pipe}
\end{figure}
Když analyzátor vyhodnotí, že v příkazu je roura, vrátí jako použitý příkaz \texttt{pipe} a příkaz s argumenty na levé straně mu zadá jako první argument a příkaz s argumenty na pravé straně jako druhý argument. Pomocí \texttt{IProcessCreatoru} je vytvořen proces \texttt{Pipe}.
\par
Třída \texttt{Pipe} pak nechá zanalyzovat oba příkazy ze svých a argumentů. Vytvoří \texttt{PipeStream} a handly obou příkazů. V těchto handlech pak nastaví prvnímu výstup a druhému vstup na svůj \texttt{PipeStream}. Následně oba procesy pomocí \texttt{IProcessCreatoru} vytvoří, spustí a počká na jejich skončení.


\subsection{Implementace}

\subsubsection{Třída ProcessCreator pro vytváření procesů}
 V době překladu a spuštění samotná aplikace nemá informace o tom, které příkazy lze zpracovávat. Třída \texttt{ProcessCreator} implementující rozhraní \texttt{IProcessCreator} je určena k vytváření nových procesů pro zpracování příkazů od uživatele, k čemuž využívá \textit{reflexi}.
\par
Na základě jména požadovaného příkazu, který je spolu s dalšími informacemi předán příslušné metodě instance třídy \texttt{ProcessCreator}, která zjistí, zda existuje třída stejného jména s požadovaným konstruktorem ve speciálním balíku \texttt{imple\-men\-ta\-tion1.\-app.co\-mma\-nds}. V tomto balíku se nacházejí přeložené třídy s implementacemi všech příkazů. Pokud je nalezena a má požadovaný konstruktor, je tato třída dynamicky načtena do paměti a následně z ní vytvořena instance procesu pro zpracovaní zadaného příkazu. Tato instance je nakonec vrácena volajícímu objektu.

\subsubsection{Synchronizace vláken procesů}
Na obrázku (viz obrázek \ref{prubehaplikace}) je znázorněn běh vláken jednotlivých procesů. Modrou barvou je označen běh uživatelských prostředí z knihovny \textit{Swing}. Proces \texttt{InitProcess} má na starosti pouze spuštění hlavního přihlašovacího okna implementující rozhraní \texttt{IMainWindow}, poté uspán a je probuzen až ve chvíli, kdy přijde požadavek na uzavření aplikace:
\begin{itemize}
\item příkaz \textit{shutdown} nebo \textit{kill}
\item  zavření přihlašovacího okna
\item volání metody \texttt{quit()} nebo \texttt{terminate()} jiným procesem nad \texttt{InitProcess}
\end{itemize}
Po probuzení zavře přihlašovací okno, zavře všechny potomky a skončí.

\begin{figure}[h!]
\centering
\includegraphics[scale=1.00]{obr/prubehaplikace}
\caption{Znázornění běhu vláken procesů.}
\label{prubehaplikace}
\end{figure}
\par
Na obrázku je dále znázorněn běch procesů \textit{shell} červenou barvou, které jsou vytvářeny po přihlášení uživatele nebo zadání příkazu \textit{shell}. Vlákno shellu běží pouze při počáteční inicializaci, vytvoření procesu pro nový příkaz a svém zavření. V ostatních případech čeká na vstup nebo na dokončení procesu potomka. Čekání na potomka je realizováno voláním metod \texttt{wait()} a \texttt{notifyAll()} nad monitorem instance třídy s procesem potomka. Na~obrázku ve spodní části je naznačeno, jak probíhá standardní ukončení shellu (odhlášení uživatele z VM, pokud je ukončován rodičovský shell). 

\subsubsection{Synchronizace na úrovni streamů}
Ve chvíli, kdy chce proces číst nebo zapisovat do určitého streamu, musí si tento stream otevřít s nastavením pro čtení, nebo pro zápis. Při otevření streamu procesem dojde k jeho uzamčení, aby ke streamu neměl přístup žádný jiný proces. Ve chvíli, kdy proces dokončí práci se streamem, zavře ho, čímž uvolní stream pro další procesy. K popsané synchronizaci přístupu je použit synchronizační prostředek typu \textit{semafor}.
\par
Operace zápisu do streamu je obecně neblokující. Operace čtení je u streamů \texttt{StdStream} a \texttt{PipeStream} blokující.  
\par
Standardní \texttt{StdStream} je svázán s uživatelským rozhraním shellu \texttt{ShellWindow} implementující rozhraní \texttt{IShellWindow}. Toto rozhraní používá pro komunikaci s GUI. Při čtení ze standardního vstupu je proces zablokován na úrovni uživatelského rozhraní \texttt{ShellWindow}, ve kterém je následně dočasně povolena možnost zadat vstup (viz obrázek \ref{stdstream}). Po potvrzení vstupu klávesou ENTER je čekající proces probuzen a přes stream je mu předán nový vstup. V případě uzavření okna nebo stisku zkratky CTRL+D pro ukončení vstupu je též proces probuzen, ale do streamu je vrácen vstup s hodnotou \textit{null}, což stream rozpozná jako ukončení vstupu a vyhodí vyjímku \texttt{StreamEOFException}. Tato vyjímka je využita u všech streamů pro indikaci konce vstupu při pokusu o čtení.

\begin{figure}[h]
\centering
\includegraphics[scale=0.7]{obr/stdstream}
\caption{Komunikace přes StdStream}
\label{stdstream}
\end{figure}
\par
\texttt{PipeStream} je primárně určen pro zajištění jednosměrné komunikace mezi procesy. V stejnou dobu je nutné umožnit otevření streamu dvěma procesům  (prvnímu pro zápis, druhému pro čtení). Z toho důvodu si \texttt{PipeStream} drží informaci o procesu, který ho otevřel pro čtení, a o procesu, který ho otevřel  pro zápis. Informace o příslušném procesu je držena skrz jeho vlákno \texttt{Thread}. Tímto způsobem je docíleno toho, že při ukončení komunikace a zavření streamu procesem dojde k uvolnění správného konce streamu.

\begin{figure}[h]
\centering
\includegraphics[scale=0.8]{obr/pipestream}
\caption{Komunikace přes PipeStream}
\label{pipestream}
\end{figure}
\par
Proces, který se pokusí číst z \texttt{PipeStream} je nad ním uspán, pokud je prázdný, do~doby, než jiný proces do fronty streamu zapíše další řádek se vstupem. K synchronizaci této komunikace, která je naznačena na obrázku (viz obrázek \ref{pipestream}), je využit \textit{monitor} příslušné instance třídy \texttt{PipeStream} a metody \texttt{wait()} a \texttt{notifyAll()}.

\subsubsection{Hierarchie procesů}
Hierarchie procesů má podobu stromu (viz obrázek \ref{hierarchieproc}). Kořenem je hlavní proces, v aplikaci je reprezentován objektem třídy \texttt{InitProcess}. Všechny procesy uživatele vznikají pod ním. Každý proces si drží v sobě seznam referencí na potomky (černé šipky na obrázku) a referenci na rodičovský proces (červené šipky). Touto hierarchií je umožněn přístup procesu ke svým bratrům přes rodiče, kořenovému procesu, atd.

\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/hierarchieprocesu}
\caption{Hierarchie procesů.}
\label{hierarchieproc}
\end{figure}

\subsubsection{Analyzátor}
Analyzátor slouží k rozdělení zapsaného příkazu na jméno příkazu, jeho parametry a dále přesměrování. Parametry příkazu i přesměrování nejsou omezeny počtem ani pořadím. Pokud dojde k zapsání několikanásobného přesměrování jednoho typu, platí vždy to poslední, tedy \texttt{command >output.txt >output2.txt} bude vypisovat výstup do \texttt{output2.txt}.\newline
Analyzátor musí v prvé řadě detekovat, zda dodaný příkaz neobsahuje \texttt{pipe}, tzv. rouru. Pokud ano, jedná se vlastně o jeden příkaz s dvěma parametry (před a za znakem \texttt{pipe}). Teprve pokud se tento případ vyloučí, následuje (bezprostředně po "nastavení" příkazu) parsování parametrů příkazu a také přesměrování jeho výstupu (\texttt{<} pro vstup, \texttt{>} pro výstup a \texttt{2>} pro chybový výstup).\newline
Příkaz je parsován podle následující gramatiky:\newline
PRIKAZ –$>$ BZ COMMAND {PEVNAMEZERA PARAMETRY BZ} { ‘$|$’ BZ PRIKAZ}\newline
COMMAND –$>$ \textit{slovo}\newline
BZ -$>$ PEVNAMEZERA $|$ e\newline
PEVNAMEZERA -$>$ \textit{mezera} {PEVNAMEZERA}\newline
PARAMETRY –$>$ [PARAMETR $|$ PRESMEROVANI] {PEVNAMEZERA PARAMETRY} $|$ e\newline
PARAMETR –$>$ TEXT $|$ e\newline
TEXT -$>$ \textit{slovo} $|$ ‘"’ VICESLOV ‘"’\newline
VICESLOV -$>$ \textit{slovo} BZ {VICESLOV} $|$ e\newline
PRESMEROVANI –$>$ BZ TYP BZ \textit{slovo} $|$ e\newline
TYP –$>$ ‘$<$’ $|$ ‘$>$’ $|$ PEVNAMEZERA ‘2$>$’\newline
kde \textit{slovo} je posloupnost alfanumerických znaků a \textit{mezera} je bílý znak odpovídající ASCII 0x20.\newline
Testováním bylo potřeba ověřit, že analyzátor zvládne i velmi neobvyklé a náročné přízaky jako např.

\section{Závěr}
Na obrázku \ref{vystup} je možné vidět ukázku reakce shellu na různé druhy příkazů.
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{obr/vystup}
\caption{Ukázka funkčnosti.}
\label{vystup}
\end{figure}
\par
Program je velice snadno rozšiřitelný o nové příkazy. Nový příkaz je možné přidat vytvořením nové třídy, odděděné od \texttt{ICommand}, a souboru nápovědy v adresáři \textit{res/help}, kde jméno souboru musí odpovídat jménu příkazu s příponou \textit{.man}.
\par
Program stojí na třívrstvé architektuře. Díky modulárnímu rozdělení a přítomnosti rozhranní je možné bez problémů vyměnit grafické rozhranní či jakoukoli část aplikační logiky za jinou. Nebo na stejném návrhu vytvořit celou novou implementaci. Návrh také umožňuje přítomnost více grafických rozhranní pod různými příkazy. Implemenováno bylo pouze jedno spustitelné příkazem \texttt{shell}.
\par
Veškeré texty vypisované programem jsou obsaženy v externích soborech \textit{.properties}, které je velice snadné editovat.
\par
Veškerý přenos dat mezi moduly stojí na potomcích třídy \texttt{IStream}. Modulům je tedy jedno, s jakým konkrétním streamem komunikují a je pouze na výběru implementace, odkud a kam se data budou posílat. Tak je snadno vyřešeno přesměrování, roura a grafické prostředí je odstíněno od synchronizace.
\par
Veškeré příkazy běží paralelně. Shell vždy čeká na svého potomka (kromě jiného shellu). Díky možnosti spuštění více shellů je aplikován paralelně víceuživatelský systém.
\par
Oproti zadání jsou dále implementovány příkazy \texttt{send} a \texttt{receive}. Příkazy \texttt{sort}, \texttt{ls} a \texttt{ps} pracují s nepovinnými přepínači. Dalším rozšířením je stálé zobrazení aktuálního adresáře v promptu.
\par
Jako vylepšení práce by mohlo být grafické rozhranní transformující události myši a klávesnice na příkazy a vytvoření dalších příkazů. 
\par
Semestrální práce nám přinesla lepší zkušenosti s paralelním programováním.
\par
Práce byla rozdělena na několik částí: návrh, implementace celku, implementace příkazů, analyzátor, grafika, složení projektu a dokumentace a mezi jednotlivé lidi takto:\\
Martin Štulc: návrh, implementace celku, složení projektu, dokumentace\\
Jan Šváb: implementace celku a příkazů, složení projektu, dokumentace\\
Jan Kolena: implementace příkazů, analyzátor, grafika, dokumentace
\par
Semestrální práce se nám zdá přínosná a velice zajímavá, bohužel jeden semestr je velice krátká doba na projekt takového rozsahu.


\end{document}